#ifndef _M__SERVER__H
#define _M__SERVER__H
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include <thread>
#include <memory>
#include <assert.h>  // assert.h
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <unistd.h>
#include <time.h>
#include <netinet/in.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <signal.h>
#include <unistd.h>
#include <sys/eventfd.h>
#include <sys/timerfd.h>
#include <functional>
#include <condition_variable>

//加入一些所在文件名，行号等信息
//宏必须保证在同一行，所以\相当于继续连接上面的代码
//time() //返回从1970-1-1 00:00:00 开始到现在的秒数
//localtime() //将t这个秒数转化成当前时间，结构体中包含年月日时分秒等
//设置日志等级
#define INFO 0
#define DEBUG 1
#define ERROR 2
#define DEFAULT_LOG_LEVEL DEBUG
//不定参设置时可以用...，但是在使用不定参数时要用 ##__VA_ARGS__
#define LOG(level,format, ...) do{\
        if(level < DEFAULT_LOG_LEVEL) break;\
        time_t t = time(nullptr);\           
        struct tm *ltm = localtime(&t);\     
        char tmp[32] = {0};\
        strftime(tmp,31,"%H:%M:%S",ltm);\                         
        fprintf(stdout,"[%p %s %s,%d] " format "\n", pthread_self(),tmp, __FILE__,__LINE__, ##__VA_ARGS__);\
    }while(0)
#define INFO_LOG(format,...) LOG(INFO,format, ##__VA_ARGS__)
#define DEBUG_LOG(format,...) LOG(DEBUG,format, ##__VA_ARGS__)
#define ERROR_LOG(format,...) LOG(ERROR,format, ##__VA_ARGS__)

class Any
{
private:
    class holder       //父类，用来被继承的
    {
    public:
        virtual ~holder() {}
        virtual const std::type_info& type() = 0 ;     
        virtual holder* clone() = 0 ;           
    };

    //子类才是用来保存数据的
    template<class T>
    class placeholder : public holder      //子类继承父类
    {
    public:
        placeholder(const T& val) : _val(val) {}  //内置类型不做处理，自定义类型T会调用它的拷贝构造
        // 获取子类对象的数据类型
        virtual const std::type_info& type() { return typeid(T); } 
        // 针对当前子类对象自身，克隆一个新的子类对象
        virtual holder* clone() { return new placeholder(_val); }
    public:
        T _val;
    };

    holder* _content;

public:
    Any() :_content(nullptr) {}
    template<class T>
    Any(const T& val) : _content(new placeholder<T>(val)) {}               //根据数据类型构造一个Any对象
    Any(const Any& other) : _content(other._content == nullptr ? nullptr : other._content->clone()) {}     //拷贝构造
    //这里的拷贝构造不能直接复制一个other地址，而是要复制other对象内的父类指针指向的子类对象(placeholder)的地址
    ~Any() {delete _content;}

    Any& swap(Any& other)  //加了const后，other的_content是const修饰的，而原本的_content是可修改的
                                //这样就会出现权限放大的情况
    {
        std::swap(_content, other._content); 
        return *this;    //返回对象本身是为了支持连续swap操作/赋值操作
    }

    template<class T> 
    T* get()                       //返回子类对象保存的数据的指针
    {
        //我当前保存的数据类型与想要返回的数据类型不匹配
        assert(typeid(T) == _content->type()) ; //条件成立继续，不成立报错

        return &(((placeholder<T>*)_content)->_val);
        // _content是一个父类指针，先转化成子类.
    }

    template<class T>
    Any& operator=(const T& val)    //赋值运算符重载
    {
        Any(val).swap(*this); //为val构造一个临时Any通用容器对象，然后与自身Any容器的_content指针交换
        //交换后不会再关心自身容器的_content了，因为交换之后，临时对象出了作用域会调用析构函数进行销毁
        
        //此时保留的就是val构造出来的_content;
        return *this;  // 为了支持连续赋值
    }

    Any& operator=(const Any& other)
    {
        Any(other).swap(*this);
        //调用拷贝构造为other对象构造一个新的临时Any对象，用该对象与我自身的_content指针交换，交换后
        //原来_content指针保存的数据就跟随临时对象调用析构销毁了

        //这样既不影响到other，又能销毁原指针指向的数据。
        return *this;   //支持连续的赋值重载
    }

};

#define DEFAULT_BUFFER_SIZE 1024
class Buffer
{
private:
    std::vector<char> _buffer;
    uint64_t _read_index;   //读偏移
    uint64_t _write_index;  // 写偏移

public:
    Buffer() : _read_index(0),_write_index(0),_buffer(DEFAULT_BUFFER_SIZE) {}
    char* Begin() { return &(*_buffer.begin());} // .begin是一个迭代器,*获取到begin位置的元素
    //1.获取当前起始读位置
    char* GetReadPos(){ return Begin() + _read_index ;}
    //2.获取当前起始写位置   
    char* GetWritePos(){ return Begin() + _write_index ;}
    //3.确保buffer有足够空间写入
    void EnsureWriteSpace(uint64_t len)
    {
        //如果末尾空闲空间足够，则不作处理
        if(GetTailAvailableSize() >= len)   return;
        //如果末尾空闲空间不够，则加上read之前的空间判断是否足够，够了就将数据移动到起始位置
        if(GetTailAvailableSize() + GetHeadAvailableSize() >= len)  
        {   
            uint64_t osz = GetReadableSpace(); //先保存当前可读数据大小
            //将数据移动到起始位置
            std::copy(GetReadPos(),GetReadPos() + osz, Begin());
            //更新读写指针
            _read_index = 0;
            _write_index = osz;
        }
        else
        {
            //空间不够，扩容
            _buffer.resize(_write_index + len);
            DEBUG_LOG("resize: %d",_write_index + len);
        }
    }
    //4.获取read之前的空间大小
    uint64_t GetHeadAvailableSize()
    { 
        return _read_index ;
    }
    //5.获取write前沿空间大小，write之后的空间
    uint64_t GetTailAvailableSize() 
    { 
        return _buffer.size() - _write_index ; 
    }
    //6.将写入位置向后移动指定长度
    void MoveWriteOffset(uint64_t len) 
    { 
        if(len == 0)    
            return;
        assert(len <= GetTailAvailableSize());//写位置移动的长度不得超过后沿可用空间
        //此时代码没有实现如果前沿有可用空间就整体往前挪
        _write_index += len; 
    }
    //7.将读取位置向后移动指定长度
    void MoveReadOffset(uint64_t len)
    {
        if(len == 0)    
            return;
        assert(len <= GetReadableSpace()); //读位置移动的长度不得超过可读大小
        _read_index += len;
    }
    //8.获取可读空间大小
    uint64_t GetReadableSpace()
    {
        return _write_index - _read_index ;
    }
    //10.写入数据
    void Write(const void* data,uint64_t len) //将data写入到_buffer容器，写len长度
    {
        //1.确保有足够的空间能够写入   2.拷贝数据
        EnsureWriteSpace(len);
        //2.拷贝数据
        const char* d = (const char*)(data);
        std::copy(d,d + len, GetWritePos());
        //3.移动写指针
        MoveWriteOffset(len); //这里视频上另外封装了几个接口，单独调用MoveWriteOffset这个函数，我觉得没必要，不搞了。
    }
    void WriteString(const std::string &data)
    {
        Write(data.c_str(),data.size());
    }  
    void WriteBuffer(Buffer& data)
    {
        Write(data.GetReadPos(),data.GetReadableSpace());
    }
    //11.读取数据
    void Read(void* buf, uint64_t len) // 将要读取的len长度数据放入到buf中
    {
        //要读取的数据长度不得超过可读数据长度
        assert(len <= GetReadableSpace());
        std::copy(GetReadPos(),GetReadPos() + len, (char*)buf);

        //移动读指针
        MoveReadOffset(len);
    }

    std::string ReadString(uint64_t len)
    {
        assert(GetReadableSpace() >= len);
        std::string str;
        str.resize(len);
        Read(&str[0],len);  
        return str;
    }

    //寻找回车换行字符
    char* FindCRLF()
    {
        char* res =(char*)memchr(GetReadPos(),'\n',GetReadableSpace());
        if(res == nullptr)  return nullptr;
        return res;
    }

    //获取一行数据，连带'\n'也提取出来
    std::string GetLine()
    {
        char* pos = FindCRLF();
        if(pos == nullptr)
            return "";
        return ReadString(pos - GetReadPos() + 1);
        //只要调用了Read，都不需要再单独设计接口调用MoveReadOffset了
    }

    //9.清理buffer
    void Clear()
    {
        _read_index = _write_index = 0;
    }
};

#define MAX_LISTEN 1024
int i = 1;
class Socket
{  
private:
    int _sockfd;
public:
    Socket():_sockfd(-1) {}
    Socket(int sockfd):_sockfd(sockfd) {}
    ~Socket() { Close(); }
    int FD()
    {
        //printf("第%d次的Socket的fd是：%d\n",i++,_sockfd);
        return _sockfd; 
    }
    //创建套接字
    bool Create()
    {
        //int socket(int domain,int type,int protocal)
        // 地址域类型：IPV4/IPV6,套接字类型，协议类型：TCP/UDP
        _sockfd = socket(AF_INET,SOCK_STREAM, 0/*IPPROTO_TCP*/);
        if(_sockfd < 0)
        {
            ERROR_LOG("create sockfd fail !!!");
            return false;
        }
        return true;
    }
    //绑定套接字(获取地址信息)
    bool Bind(const std::string& ip,uint16_t port)
    {
        //1.初始化绑定信息
        sockaddr_in addr ;
        addr.sin_family = AF_INET; //IPV4
        addr.sin_port = htons(port); //主机序转网络字节序
        addr.sin_addr.s_addr = inet_addr(ip.c_str()); //同上
        socklen_t len = sizeof(sockaddr_in);
        //2.int bind(int socket,struct sockaddr* addr,socklen_t len);
        int ret = bind(_sockfd,(sockaddr*)&addr,len);
        if(ret < 0)
        {
            ERROR_LOG("bind address fail!!!");
            return false;
        }
        return true;
    }
    //监听套接字
    bool Listen(int backlog = MAX_LISTEN) //最大并发监听数量backlog（同一时间）,但是不限制最大监听数量
    {
        int ret = listen(_sockfd,backlog);
        if(ret < 0)
        {
            ERROR_LOG("listen socket fail!!");
            return false;
        }
        return true;
    }

    //向服务器发起新链接
    bool Connect(const std::string& ip,uint16_t port)
    {
        //1.初始化绑定信息
        sockaddr_in addr;
        addr.sin_family = AF_INET; //IPV4
        addr.sin_port = htons(port); //主机序转网络字节序
        addr.sin_addr.s_addr = inet_addr(ip.c_str()); //同上
        socklen_t len = sizeof(sockaddr_in);
        //2.int connect(int socket,struct sockaddr* addr,socklen_t len);
        int ret = connect(_sockfd,(sockaddr*)&addr,len);
        if(ret < 0)
        {
            ERROR_LOG("Connect Server fail!!!");
            return false;
        }
        return true;
    }

    //服务器获取新链接 , 有多个链接已经就绪，获取新链接进行处理
    int Accept()
    {
        //int accept(int socket,struct sockaddr* addr,soclen_t* len);
        int newfd = accept(_sockfd,nullptr,nullptr); //这里暂时不关心地址信息
        if(newfd < 0)
        {
            ERROR_LOG("socket new Accept fail!!!");
            return -1;
        }
        return newfd;
    }

    //接受数据 (默认阻塞)
    ssize_t Recv(void* buf,size_t len,int flag = 0) //flag发送方式：阻塞和非阻塞
    {
        if(len == 0)    return 0;
        //ssize_t recv(int socket,void* buffer, size_t len ,int flag);
        ssize_t ret = recv(_sockfd,buf,len,flag);
        if(ret < 0) // <0 错误， = 0没有接收到数据 , > 0实际接收到数据的长度
        {
            //EAGAIN 表示当前socket的接收缓冲区数据没有了，在非阻塞的情况下在会出现这个可以原谅的错误
            //EINTR  表示当前socket的阻塞等待被signal信号打断了，我当前在阻塞等数据呢，你发信号过来打断我了
            if(errno == EAGAIN || errno == EINTR)
            {
                return 0; 
            }
            ERROR_LOG("socket recv fail: %s:%d",strerror(errno));
            return -1;
        }
        //std::cout << "server Get a message: " << (char*)buf << std::endl;
        return ret;
    }

    ssize_t NonBlockRecv(void* buf,size_t len)  //设置为非阻塞接收数据
    {
        if(len == 0)    return 0;
        return Recv(buf,len,MSG_DONTWAIT); // MSG_DONTWAIT表示当前接收为非阻塞
    }

    //发送数据 (默认阻塞)
    ssize_t Send(const void* buf,size_t len,int flag = 0)
    {
        //ssize_t send(int socket,void* buf, size_t len, int flag);
        ssize_t ret = send(_sockfd,buf,len,flag);
        if(ret < 0)
        {
                if(errno == EAGAIN || errno == EINTR)
            {
                return 0; 
            }
            ERROR_LOG("Socket send message fail,%s:%d",strerror(errno));
            return -1;
        }
        //std::cout <<"server Send a message: " << (char*)buf << std::endl;
        return ret; //返回实际写入的数据长度
    }

    ssize_t NonBlockSend(void* buf,size_t len)  //设置为非阻塞发送数据
    {
        if(len == 0)    return 0;
        return Send(buf, len, MSG_DONTWAIT); // MSG_DONTWAIT表示当前发送为非阻塞
    }

    //关闭套接字
    void Close()
    {
        //避免重复调用Close
        if(_sockfd != -1)
        {
            DEBUG_LOG("Close socket %d", _sockfd);
            close(_sockfd);
            _sockfd = -1;
        }
    }

    //创建一个服务端绑定特定的地址和IP，等待客户端发起新连接。
    bool CreateServer(uint16_t port,const std::string& ip = "0.0.0.0",bool block_flag = false) //阻塞方式默认是阻塞
    {
        //1.创建套接字  2. 绑定地址信息  3.监听套接字  4.设置非阻塞属性  5.开启地址重用
        if(Create() == false )  return false;
        if(block_flag)  NonBlock();
        ReuseAddress(); 
        if(Bind(ip,port) == false)  return false;
        if(Listen() == false)   return false;
        
        return true;
    }
    //创建客户端链接到服务器
    bool CreateClient(uint16_t port,const std::string& ip)
    {
        //1.创建套接字   2.连接服务器
        if(Create() == false)   return false;
        if(Connect(ip,port) == false)
        {
            ERROR_LOG("client connect server fail,err:%s ",strerror(errno));
            Close();
            return false;
        }   

        return true;
    }
    //创建套接字设置套接字可选选项：打开地址和端口重用绑定套接字（获取地址信息）
    //端口重用选项（SO_REUSEADDR）允许在同一地址和端口上绑定多个套接字，常用于多线程服务器和快速重启服务器程序。
    void ReuseAddress()
    {
        //int setsockopt(int socket,int level,int opt_name,void* opt_val,socklen_t opt_len);
        int val = 1;
                                    //SOL_SOCKET是对套接字操作级别
        int ret = setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR,(void*)&val,sizeof(val));
        val = 1;
        int ret1 = setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT,(void*)&val,sizeof(val));

    }

    //设置套接字阻塞属性-非阻塞监听套接字向服务器发起新链接如果是阻塞状态，当缓冲区数据被读取完后获取新链接会阻塞住，这是不可取的。
    void NonBlock() 
    {
        //int fcntl(int fd, int cmd, ...);
        //1.先获取_sockfd的属性（是一个位图） 2.再将O_NONBLOCK非阻塞属性设置进去
        int flag = fcntl(_sockfd,F_GETFL,0);
        
        fcntl(_sockfd,F_SETFL, flag | O_NONBLOCK);
    }
};

//对文件描述符的监控事件管理类
class Poller; //只是声明下面有Poller这个类，但是要想调用类内成员函数还不行
class EventLoop;

class Channel
{
private:
    int _fd;
    EventLoop* _loop;
    uint32_t _events;   //要监控的事件
    uint32_t _revents;  //当前描述符对应的连接触发的事件
    using EventCallBack = std::function<void()>;
    EventCallBack _read_callback;            //可读事件被触发的回调函数
    EventCallBack _write_callback;          //可写事件被触发的回调函数
    EventCallBack _error_callback;          //错误事件被触发的回调函数
    EventCallBack _close_callback;          //挂断事件被触发的回调函数
    EventCallBack _events_callback;         //任意事件被触发的回调函数
public:
//参数1：谁管我，参数2：我管谁
    Channel(EventLoop* loop,int fd): _fd(fd),_events(0),_revents(0),_loop(loop) {}

    ~Channel(){}
    
    int Fd(){ return _fd; }
    void SetReadCallback(const EventCallBack& cb){ _read_callback = cb; }       //设置可读事件回调
    void SetWriteCallback(const EventCallBack& cb){ _write_callback = cb; }    //设置可写事件回调
    void SetErrorCallback(const EventCallBack& cb){ _error_callback = cb; }    //设置错误事件回调
    void SetCloseCallback(const EventCallBack& cb){ _close_callback = cb; }    //设置挂断事件回调
    void SetEventsCallback(const EventCallBack& cb){ _events_callback = cb; }   //设置任意事件回调
    void SetRevents(const uint32_t events){ _revents = events; }                //事件就绪后，交给_revents触发
    uint32_t Events() { return _events; }  // 返回要监控的事件
    //后面实现了Eventloop类后，会完善下面的函数
    bool ReadAble()                     //描述符是否监控了可读
    {
        return (_events & EPOLLIN);
    }
    bool WriteAble()                    //描述符是否监控了可写
    {
        return (_events & EPOLLOUT);
    }
    void EnableRead()                   //对描述符监控可读 (启动读事件监控)
    {
        _events |= EPOLLIN;
        Update();
    }
    void EnableWrite()                  //对描述符监控可写(启动写事件监控)
    {
        _events |= EPOLLOUT;
        Update();
    }
    void DisableRead()                  //解除可读事件监控  (没移除，还能恢复)
    {
        _events &= (~EPOLLIN);
        Update();
    }
    void DisableWrite()                 //解除可写事件监控  (没移除，还能恢复)
    {
        _events &= (~EPOLLOUT);
        Update();
    }
    void DisableAll()                   //解除所有事件监控
    {
        _events = 0;
        Update(); 
    }

    //update和remove就是将poller和channel整合起来了。
    void Remove();                     //从epoll模型（红黑树）中移除该事件监控
    void Update();                     //可以在Channel模块中自动添加进Poller中管理
    
    void HandleEvent()                  //事件处理，一旦连接触发了事件，就调用该函数处理，具体什么事件会根据_revents来判断
    {
        //如果读事件就绪 | 相关连接断开了,上层则要求要读完缓冲区的数据 |  优先带外数据
        if((_revents & EPOLLIN) || (_revents & EPOLLRDHUP) || (_revents & EPOLLPRI))
        {
            if(_read_callback)  _read_callback();
        }
        
        if((_revents & EPOLLOUT))
        {
            if(_write_callback)  _write_callback();
        }
        else if((_revents & EPOLLERR))
        {
            if(_error_callback)  _error_callback();
        }
        else if((_revents & EPOLLHUP))
        {
            if(_close_callback)  _close_callback();
        }
        //再调用完所有事件后再调用任意时间回调刷新活跃度
        //放到最后再调用任意事件回调
        if(_events_callback)    _events_callback();
    }

};

//最大监控数
#define MAX_EPOLLEVENTS 1024
class Poller
{
private:
    int _epfd;
    struct epoll_event _evs[1024]; //保存就绪事件（epoll_wait）
    std::unordered_map<int,Channel*> _channels; // 监听的描述符和对应描述符的事件管理对象
private:
    //直接对epoll模型的红黑树操作
    void Update(Channel* channel,int op)
    {
        //向epoll模型添加事件监控
        //int epoll_ctl(int epfd,int op, int fd, struct epoll_event* event);
        int fd = channel->Fd();
        struct epoll_event eve;
        eve.data.fd = fd; //用户要监控的描述符
        eve.events = channel->Events(); //要监控的事件
        
        int ret = epoll_ctl(_epfd, op, fd, &eve);
        //std::cout << "epfd: " << _epfd << " " << op << " " <<"fd: " << fd << " " << "eve.events: " << eve.events << std::endl; 
        if(ret < 0)
        {
            ERROR_LOG("epoll_ctl fail! op=%d fd=%d err:%s", 
             op, fd, strerror(errno)); // 添加操作类型和错误详情
        }
        return;
    }  

    //判断一个Channel是否已经添加事件监控
    bool HasChannel(Channel* channel)
    {
        auto it = _channels.find(channel->Fd());
        if(it == _channels.end())
            return false;
        return true;
    }
    
//对外提供的接口
public:
    Poller() 
    {
        //创建epoll模型
        _epfd = epoll_create(MAX_EPOLLEVENTS); //现在的epoll_create已经不限制最大监控数量了，这里传一个非0数字即可
        if(_epfd < 0)
        {
            ERROR_LOG("epoll fail! err string: %s",strerror(errno));
            abort(); //程序给自己发信号退出程序
        }
    }
    //添加/修改监控事件
    void UpdateEvent(Channel* channel)
    {
        //判断是否存在
        bool ret = HasChannel(channel);
        if(ret == false)
        {
            //添加之前需要将该channel放进channels中管理起来
            _channels.insert(std::make_pair(channel->Fd(),channel));
            //不存在则添加
            Update(channel,EPOLL_CTL_ADD);
        }
        //存在则修改
        else
        {
            Update(channel,EPOLL_CTL_MOD);
        }
    }
    //移除监控事件
    void RemoveEvent(Channel* channel)
    {
        //1.先将channel事件从epoll模型移除
        Update(channel,EPOLL_CTL_DEL);

        //2.再将channel事件从unordered_map管理中移除
        auto it = _channels.find(channel->Fd());
        if(it != _channels.end())
            _channels.erase(it);
    }

    //开始监控，返回活跃链接，这里是一个输出型参数
    void Poll(std::vector<Channel*>* active)
    {
        //1.监听                              2.在哈希表中取出就绪描述符对应的channel事件管理对象
        //3.将就绪事件交给该channel对象处理    4.返回就绪的链接给上层
        //监听函数，返回监听的事件中就绪的事件个数
        //int epoll_wait(int epfd,struct epoll_event* evs,int maxeves,int timeout)
        //                                                                -1是阻塞，阻塞监听，直到有事件就绪，
        //                                                                 设置成其他的话，就是非阻塞，每隔timeout秒就循环一次
        int nfds = epoll_wait(_epfd,_evs,MAX_EPOLLEVENTS,-1); //阻塞
        if(nfds < 0)
        {
            if(errno == EINTR) //被信号终止
                return;
            ERROR_LOG("EPOLL WAIT ERROR : %s\n",strerror(errno));
            abort(); //程序给自己发信号退出
        }

        //对就绪事件处理
        for(int i = 0;i < nfds;i++)
        {
            auto it = _channels.find(_evs[i].data.fd);
            assert(it != _channels.end()); //如果在哈希表中找不到该就绪事件，说明我的代码写的有问题，这里assert方便调试
            it->second->SetRevents(_evs[i].events) ; //将就绪事件交给对应channel处理
            //it是unordered_map的键值对,it->second就是 channel* ,一个单独的channel对象指针
            active->push_back(it->second);           //返回就绪连接
        }
        return ;
    }
    
};

//定时器任务对象作用是封装定时任务
using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _id;           //定时器任务对象id
    uint32_t _timeout;      //定时器任务超时时间
    TaskFunc _task_cb;      //定时器对象要执行的定时任务
    bool _canceled;         //取消定时任务，false表示不取消，true表示取消
    ReleaseFunc _release;   //删除TimerWheel中保存的定时器对象信息
public:
    TimerTask(uint64_t id,uint32_t delay,const TaskFunc& task_cb)
        :_id(id),_timeout(delay),_task_cb(task_cb),_canceled(false)
    {}

    void SetRelease(const ReleaseFunc& cb){ _release = cb; } //设置具体的Release回调
    void Cancel(){_canceled = true; }
    int DelayTime() {return _timeout;}

    ~TimerTask()
    {
        if(_canceled == false) _task_cb();
        _release();
    }
};

//时间轮
//是通过shared_ptr来管理定时器任务对象
class TimerWheel
{
private:
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;

    int _tick;      //当前时间轮的秒针，走到哪里释放哪里，就是通过调用shard_ptr来执行该位置的定时器任务
    int _capacity;  //轮盘最大数量，其实就是最大延迟时间。
    std::vector<std::vector<PtrTask>> _wheel; //时间轮(保存的每个对象都是shared_ptr)
    std::unordered_map<uint64_t,WeakTask> _timers; // 所有的定时器任务对象
    //当定时器任务对象真的要释放时，WeakTask也要释放

    //注意成员定义的顺序，成员被初始化看的是定义顺序而不是初始化列表中的顺序
    //这里就踩了坑
    EventLoop* _loop;
    int _timefd; //定时器描述符
    std::unique_ptr<Channel> _timer_channel; //为定时器描述符创建一个channel来提供服务，为timerfd设置事件回调
    
private:
    //创建_timerfd
    static int Createtimefd()
    {
        //1.创建定时器
        int timerfd = timerfd_create(CLOCK_MONOTONIC,0);
        if(timerfd < 0)
        {
            ERROR_LOG("timerfd create fail!!\n");
            abort();    
        }
        itimerspec itime;
        itime.it_value.tv_sec = 2; //第一次超时时间
        itime.it_value.tv_nsec =0;

        itime.it_interval.tv_sec = 1 ;//往后每次超时间隔时间
        itime.it_interval.tv_nsec =0;
        //2.启动定时器
        timerfd_settime(timerfd,0, &itime,nullptr);

        return timerfd;
    }

    //读取定时器描述符
    int Readtimefd()
    {
          //有可能因为其他描述符的事件处理花费事件比较长，然后在处理定时器描述符事件的时候，有可能就已经超时了很多次
            //read读取到的数据times就是从上一次read之后超时的次数
        uint64_t times;
        int ret = read(_timefd,&times,8); //默认阻塞读取，直到有数据到来
        if(ret < 0)
        {
            ERROR_LOG("read timerfd error");
            abort();
        }
        return times;
    }
    //秒针滴答滴答往后走
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();              //秒针走到哪里，就会把vector中所有管理定时器任务对象的share_ptr都释放。
                                            //shared_ptr释放前会释放它自身管理的对象，也就是定时器任务对象，释放时定时任务对象就会调用
                                            //析构函数，析构函数中就有对应的任务回调函数
    }

    void OnTime()
    {
        int times = Readtimefd();
        //超时几次，执行几次定时任务
        for(int i = 0;i < times;i++)
        {
            RunTimerTask();
        }
    }

    //从时间轮中删除定时器对象
    void RemoveTimer(uint64_t id) //注意类内成员函数的第0个参数都是this指针
    {
        auto it = _timers.find(id);
        if(it != _timers.end())
        {
            _timers.erase(it);
        }
    }
    
    void TimerAddInLoop(uint64_t id, uint32_t delay,const TaskFunc& task_cb) //添加定时任务
    {
        PtrTask pt(new TimerTask(id,delay,task_cb));     //1.为定时任务设置shared_ptr管理
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer,this,id));  //2.为定时任务设置完成后释放回调函数
                                //必须加&以及类名
        int pos = (_tick + delay) % _capacity;           
        _wheel[pos].push_back(pt);                       //3.将shared_ptr添加进时间轮
        _timers[id] = WeakTask(pt);                      //4.构造weak_ptr加入哈希表进行管理
    }   
    
    void TimerRefreshInLoop(uint64_t id)
    {
        //通过保存对象的weak_ptr来构造一个shared_ptr，并添加到轮子中
        auto it = _timers.find(id);
        if(it == _timers.end())
            return ;
        PtrTask pt = it->second.lock(); // lock:获取该weak_ptr管理对象的shared_ptr
        int delay = pt->DelayTime();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }
        //取消定时任务
    void TimerCancelInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
            return ;
        PtrTask pt = it->second.lock(); //获取weak_ptr对应的shared_ptr;
        if(pt) pt->Cancel();                
    }                                   

public: 
    TimerWheel(EventLoop* loop) :_tick(0),_capacity(60),_wheel(_capacity)
    ,_loop(loop),_timefd(Createtimefd()),_timer_channel(new Channel(loop,_timefd))
    {
        _timer_channel->SetReadCallback(std::bind(&TimerWheel::OnTime,this)); //定时器任务触发读事件后，timer_channel会进行回调处理读事件
        _timer_channel->EnableRead(); //启动可读事件监控    
    }

    //添加定时任务时，会判断该任务是否属于当前线程，如果是则直接执行否则压入任务队列
    //等待就绪事件都处理完后再执行任务队列的任务(不想加锁的写法，不加锁的话就把所有对定时器的操作都放在同一个线程中执行)
    void TimerAdd(uint64_t id, uint32_t delay,const TaskFunc& task_cb);
    
    //同理
    void TimerRefresh(uint64_t id); //刷新定时任务,如果在TimerAdd里指定的添加定时任务的延时时间是5s，那么刷新定时任务后，还是延时5秒才销毁
    void TimerCancel(uint64_t id);

    //存在线程安全问题，所以不能被外界使用，只能在模块内部使用，只能在EventLoop里面调用
    bool HasTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
            return false;
        return true;
    }

};

class EventLoop
{
private:
    std::thread::id _thread_id; //用于对比当前线程的任务是否要放入任务队列中 
    //如果是当前线程的任务就不需要放入任务队列
    //如果是其他线程的任务就要放入任务队列

    int _event_fd; //eventfd唤醒IO事件监控中有可能导致阻塞的东西
    std::unique_ptr<Channel> _event_channel; //对_event_fd管理
    //使用unique_ptr对Channel*进行管理，一旦EventLoop释放了，unique_ptr也会跟着释放，它管理的Channel*就会释放
    //当 unique_ptr 超出作用域或被重置时，它会自动释放所管理的内存。
    Poller _poller;//监控所有事件

    using Functor = std::function<void()>;
    std::vector<Functor> _tasks;// 任务池，所有的具体操作都封装起来放到任务池，等就绪事件都处理完成后再一一处理这些任务。
    std::mutex _mutex; // 实现任务池操作的线程安全
    TimerWheel _timer_wheel;

private:
    //一一执行任务池中的所有任务
    void RunAllTasks()
    {
        std::vector<Functor> functors;
        //给锁限定一个作用域，出了作用域自动解锁
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.swap(functors);
        }

        //任务的执行可以并发执行
        for(auto& f : functors)
            f();
    }

    //创建eventfd对象，实现事件通知机制
    static int CreateEventFd()
    {
        int efd = eventfd(0,EFD_CLOEXEC | EFD_NONBLOCK);
        //返回一个文件描述符用于操作
        if(efd < 0)
        {
            ERROR_LOG("Create eventfd fail!!\n"); 
            abort(); //让程序异常退出
        }
        return efd;
    }

    void ReadEventfd() //读取Eventfd的数据无非就是读取该计数器中的数据 读取到的数据就是通知的次数
    {
        uint64_t res = 0;
        int ret = read(_event_fd,&res,sizeof(res));
        if(ret < 0)
        {
            if(errno == EINTR || errno == EAGAIN) // 被信号打断 , 无数据可读
                return;
            ERROR_LOG("Read eventfd fail!!\n"); 
            abort(); //让程序异常退出
        }
        return ;
    }
    
    void WakeUpEventfd() //向Eventfd中写入数据也是，写入的就是要通知的次数
    {
        uint64_t val = 1;
        int ret = write(_event_fd,&val,sizeof(val));
        if(ret < 0)
        {
            if(errno == EINTR) // 被信号打断
                return;
            ERROR_LOG("WakeUp eventfd fail!!\n"); 
            abort(); //让程序异常退出
        }
    }
public:
    EventLoop()
        :_thread_id(std::this_thread::get_id()) //获取当前线程的id
        ,_event_fd(CreateEventFd()) 
        ,_event_channel(new Channel(this,_event_fd))
        ,_timer_wheel(this)
    {
        _event_channel->SetReadCallback(std::bind(&EventLoop::ReadEventfd,this));
        //_event_channel->SetWriteCallback(); //由于ReadEventfd是一个静态成员变量，没有this指针
                                                                        //所以要主动传一个this指针给该类的成员函数
        _event_channel->EnableRead(); //启动可读事件监控 (重要重要重要！)
    }
    //在EventLoop中让Poller开始事件监控
    void Start() //事件监控 --> 就绪事件处理 --> 开始执行任务
    {
        while(1)
        {
            std::vector<Channel*> active;
            //启动事件监控
            _poller.Poll(&active);
            //1.先处理活跃链接（就绪事件）
            for(auto &channel : active)
            {
                channel->HandleEvent();
            }
            //2.再开始执行任务
            RunAllTasks();
        }
    }

    bool IsInLoop()    //判断当前线程是否是EventLoop对应的线程
    {
        return _thread_id == std::this_thread::get_id();
    }

    void AssertInLoop()
    {
        assert(_thread_id == std::this_thread::get_id()); 
    }
    void RunInLoop(const Functor& cb) //判断将要执行的任务是否属于当前线程，如果是则执行，不是则压入就绪队列
    {
        if(IsInLoop())
        {
            return cb();
        }
        //压入任务队列
        QueueInLoop(cb);
    }

    void QueueInLoop(const Functor& cb) //将具体要执行的操作压入任务池
    {
        {
            std::unique_lock<std::mutex>  _lock(_mutex);
            _tasks.push_back(cb);
        }
        //唤醒可能因为没有事件就绪导致的任务队列阻塞。
        //因为是先处理就绪事件再处理任务队列的，假如没有事件就绪，那任务队列那些任务就得不到执行了
        WakeUpEventfd();
    }

    void UpdateEvent(Channel* channel) //添加/修改描述符的事件监控
    {
        _poller.UpdateEvent(channel);
        //channel->Update();
    }
    void RemoveEvent(Channel* channel)  //移除描述符的监控
    {
        _poller.RemoveEvent(channel);
        //channel->Remove();
    }

    //定时器的接口
    void TimerAdd(uint64_t id, uint32_t delay,const TaskFunc& task_cb)
    {
        _timer_wheel.TimerAdd(id,delay,task_cb);
    }
    
    void TimerRefresh(uint64_t id)  //刷新定时任务,如果在TimerAdd里指定的添加定时任务的延时时间是5s，那么刷新定时任务后，还是延时5秒才销毁
    {
        _timer_wheel.TimerRefresh(id);
    }   

    void TimerCancel(uint64_t id)
    {
        _timer_wheel.TimerCancel(id);
    }
    
    //判断是否有该定时任务
    bool HasTimer(uint64_t id)
    {
        return _timer_wheel.HasTimer(id);
    }

};

typedef enum
{
    DISCONNECTED, //连接关闭状态
    CONNECTING,   //连接成功等待下一步处理状态
    CONNECTED,    //连接成功，各种设置完成，可以通信状态
    DISCONNECTING //连接待关闭状态
} ConnStatu;

class Connection;

using PtrConnection = std::shared_ptr<Connection>;
class Connection : public std::enable_shared_from_this<Connection> 
{
private:
    uint64_t _conn_id; // 连接的唯一ID,便于连接的管理和查找 ，同时为了简化操作，用来做定时器的唯一ID
    //uint64_t _timer_id;
    int _sockfd;       // 连接关联的文件描述符
    ConnStatu _statu;   //连接状态
    bool _enable_inactive_release; //非活跃连接销毁 启动按钮，默认为false，启动后，非活跃链接就会被释放
    EventLoop* _loop; //连接关联一个Loop，而Loop又关联着线程，所以Connection也就关联到线程了
    Socket _socket;    // 套接字管理
    Channel _channel;  // 事件管理
    Buffer _in_buffer; //输入缓冲区，存放从socket中读到的数据
    Buffer _out_buffer;//输出缓冲区，存放要发给对方的数据
    Any _context;      //保存上次接收后处理的上下文

    //下面是各种回调处理
    using ConnectedCallback = std::function<void(const PtrConnection &)>; //连接回调处理
    using MessageCallback = std::function<void(const PtrConnection &, Buffer*)>; // 业务处理回调
    using ClosedCallback = std::function<void(const PtrConnection &)>; // 关闭连接回调
    using AnyEventCallback = std::function<void(const PtrConnection &)>;   //任意事件回调

    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _close_callback; 
    AnyEventCallback _event_callback;
    /*服务器组件内的连接关闭回调*/ 
    ClosedCallback _server_close_callback; 
    
    //五种事件回调函数
    void HandleRead() //可读事件触发后调用的函数，接收Socket的数据放到接收缓冲区中，随后调用_message_callback（业务处理回调）
    {
        //1.从Socket中读取数据放入到接收缓冲区中
        char buf[65535];
        ssize_t ret = _socket.NonBlockRecv(buf,65535);
        if(ret < 0)
            //出错了不能直接关,判断发送缓冲区是否有数据待处理，启动写事件监控
            return Shutdown(); 
        else if(ret == 0) //未读取到数据
            return ;
        //这里我的Write内部在写入数据后写指针已经向后偏移了    
        _in_buffer.Write(buf,ret);

        //2.调用_message_callback进行业务处理
        _message_callback(shared_from_this(),&_in_buffer); //获取_message_callback自身的shared_ptr对象传过去
        
        return;
    }
    
    void HandleWrite()//可写事件触发后，将发送缓冲区的数据发送
    {
        ssize_t ret = _socket.NonBlockSend(_out_buffer.GetReadPos(),_out_buffer.GetReadableSpace());
        if(ret < 0)
        {
            //判断是否有数据待处理
            if(_in_buffer.GetReadableSpace() > 0)
                _message_callback(shared_from_this(),&_in_buffer);
            //发送失败，这下真要关闭链接了
            return Release();
        }
        //发送数据后将读指针向后偏移
        _out_buffer.MoveReadOffset(ret);
        
        //如果缓冲区没有数据待发送了，就关闭写事件监控，不然只要缓冲区有剩余可写空间，就会一直触发写事件监控
        if(_out_buffer.GetReadableSpace() == 0)
        {
            _channel.DisableWrite();
            //然后判断该链接如果属于待关闭状态，是则关闭链接
            if(_statu == DISCONNECTING)
            return Release();
        }
        return ;
    }

    void HandleClose()//触发关闭事件
    {
        //先判断是否还有数据待处理，处理完就关闭链接
        if(_in_buffer.GetReadableSpace() > 0)
            _message_callback(shared_from_this(),&_in_buffer);
        
        return Release();
    }

    void HandleError()//触发错误事件调用的函数
    {
        return HandleClose();
    }
    
    void HandleEvent()//任意事件触发都会调用该函数
    {
        //1.刷新链接活跃度  2.调用任意事件回调
        if(_enable_inactive_release == true) _loop->TimerRefresh(_conn_id);

        if(_event_callback) _event_callback(shared_from_this());
    }

private:
    void EstablishedInLoop() //获取连接成功后，建立连接回调，然后启动读监控
    {
        //1.修改链接状态   2.启动读监控  3. 调用连接成功回调
        if(_statu == CONNECTING)  //之前的状态必须是连接成功待处理状态
        {
            _statu = CONNECTED;

            _channel.EnableRead();
            if(_connected_callback) _connected_callback(shared_from_this());
        }
    }

    void ReleaseInLoop() // 这个接口才是实际释放的接口
    {
        //1.修改链接状态   2.关闭连接事件监控   3.关闭描述符    4.如果当前定时任务队列还有定时销毁任务，则取消任务，
                                                            //因为这时候都要释放链接了，如果释放链接后还执行任务，就会变成野指针操作
        //5.调用close_callback回调(用户) //先用户后服务器，否则可能导致Connection释放后，再调用用户的close_callback会出错
        //6.调用_server_close_callback(移除服务器内部管理的连接信息)
        _statu = DISCONNECTED;
        _channel.Remove();
        _socket.Close();

        if(_loop->HasTimer(_conn_id)) CancelInactiveReleaseInLoop(); 

        if(_close_callback) _close_callback(shared_from_this());

        if(_server_close_callback) _server_close_callback(shared_from_this());

        //DEBUG_LOG("RELEASE FUNCTION ");
    }

    //这个接口并不是真的发送数据，而是将数据写入到发送缓冲区，并启动可写事件监控
    void SendInLoop(const char* data, size_t len) //发送数据
    //这里也可以直接传递一个Buffer& buf,然后在上一级调用时可以用一个右值引用来减少拷贝次数，提高效率(std::move(buf))
    {
        //判断当前链接状态
        if(_statu == DISCONNECTING) return ;
        //将数据写入到发送缓冲区
        _out_buffer.Write(data,len); //在Write函数内部已经将写指针往后移了
        
        if(_channel.WriteAble() == false) //判断是否启动过写事件监控
            _channel.EnableWrite();
    }

    void ShutdownInLoop() //提供给组件使用者的关闭接口，不是真的关闭，而是先判断缓冲区是否还有没处理的数据
    {
        //1.修改链接状态
        _statu = DISCONNECTING; //半关闭状态
        //2.处理接收缓冲区
        if(_in_buffer.GetReadableSpace() > 0)
            _message_callback(shared_from_this(),&_in_buffer);
        //3.处理发送缓冲区
        if(_out_buffer.GetReadableSpace() > 0)
        {
            if(_channel.WriteAble() == false) //判断是否启动过写事件监控
                _channel.EnableWrite();  //启动写事件监控，等待下一次事件触发来处理发送缓冲区的数据
        }
        //发送缓冲区没有数据可以处理了，就直接关闭链接吧
        if(_out_buffer.GetReadableSpace() == 0)
        {
            Release();
        }
        return;
    }

    void EnableInactiveReleaseInLoop(int second)//启动非活跃销毁，添加定时任务
    {
        _enable_inactive_release = true;
        //如果定时任务已经存在，则延时定时销毁任务即可
        if(_loop->HasTimer(_conn_id))   return _loop->TimerRefresh(_conn_id);
        //如果不存在，则添加定时销毁任务
        _loop->TimerAdd(_conn_id,second,std::bind(&Connection::Release,this));
    }

    void CancelInactiveReleaseInLoop()//取消非活跃销毁 ,如果有定时任务，则取消
    {
        _enable_inactive_release = false;
        if(_loop->HasTimer(_conn_id))       
            _loop->TimerCancel(_conn_id);
    }
    //切换协议并重置上下文和阶段处理函数
    void UpgradeInLoop(const Any& context,
                const ConnectedCallback& conn,
                const MessageCallback& mesg,
                const ClosedCallback& closed,
                const AnyEventCallback& event)
    {
        _context = context;
        _connected_callback = conn;
        _message_callback = mesg;
        _close_callback = closed;
        _event_callback = event;
    }

public:
    //Connected隶属_loop管理，Connected的唯一id是conn_id,Connected管理的Socket是sockfd
    
    Connection(EventLoop* loop,uint64_t conn_id,int sockfd)
        :_loop(loop),_conn_id(conn_id),_sockfd(sockfd),_socket(sockfd)
        ,_statu(CONNECTING),_enable_inactive_release(false),
        _channel(loop,sockfd)
    {
        //为_channel设置各种事件回调
        //_socket.NonBlock();
        _channel.SetCloseCallback(std::bind(&Connection::HandleClose,this));
        _channel.SetErrorCallback(std::bind(&Connection::HandleError,this));
        _channel.SetEventsCallback(std::bind(&Connection::HandleEvent,this));
        _channel.SetReadCallback(std::bind(&Connection::HandleRead,this));
        _channel.SetWriteCallback(std::bind(&Connection::HandleWrite,this));
    //注意：Channel的启动读事件监控一定不能放在构造函数中，因为如果先启动读事件监控，后面那些添加定时任务，设置回调等就会出问题
    }   

    ~Connection()
    {
        DEBUG_LOG("RELEASE CONNECTION: %p",this);
    }

    int Fd()
    {
        return _sockfd;
    }
    int Id()
    {
        return _conn_id;
    }
    bool IsConnectedStatu() //判断是否处于CONNECTED已连接成功状态
    {
        return _statu == CONNECTED;
    }
    void SetContext(const Any& context) // 设置上下文信息
    {
        _context = context;
    }
    Any* GetContext() // 获取上下文 ,返回的是指针才能拿到上次留下的上下文
    {
        return &_context;
    }
    void SetConnectedCallback(const ConnectedCallback& cb)
    {
        _connected_callback = cb;
    }
    void SetMessageCallback(const MessageCallback& cb)
    {
        _message_callback = cb;
    }
    void SetClosedCallback(const ClosedCallback& cb)
    {
        _close_callback = cb;
    }
    void SetSvrCloseCallback(const ClosedCallback& cb)
    {
        _server_close_callback = cb;
    }
    void SetAnyEventCallback(const AnyEventCallback& cb)
    {
        _event_callback = cb;
    }
    void Established() // 连接建立后，为Channel建立各种回调，并启动读监控
    {
        _loop->RunInLoop(std::bind(&Connection::EstablishedInLoop,this));
    }
    void Send(const char* data, size_t len) //发送数据
    {
        _loop->RunInLoop(std::bind(&Connection::SendInLoop,this,data,len));
    }
    void Shutdown() //提供给组件使用者的关闭接口，不是真的关闭，而是先判断缓冲区是否还有没处理的数据
    {
        _loop->RunInLoop(std::bind(&Connection::ShutdownInLoop,this));
    } 
    //将释放操作放入到任务池中， 在处理完就绪时间后再处理任务池的任务进行释放操作
    //否则：具体情况见client4的解释
    void Release()
    {
        _loop->QueueInLoop(std::bind(&Connection::ReleaseInLoop,this));
    }

    void EnableInactiveRelease(int second)//启动非活跃销毁并定义多长时间无通信被判定为非活跃，添加定时任务
    {
        _loop->RunInLoop(std::bind(&Connection::EnableInactiveReleaseInLoop,this,second));
    }
    void CancelInactiveRelease()//取消非活跃销毁
    {
        _loop->RunInLoop(std::bind(&Connection::CancelInactiveReleaseInLoop,this));
    }
    //切换协议并重置上下文和阶段处理函数
    void Upgrade(const Any& context,
                const ConnectedCallback& conn,
                const MessageCallback& mesg,
                const ClosedCallback& closed,
                const AnyEventCallback& event)
    {
        //该函数必须在线程内立即执行 ，防备新的事件触发后，处理的时候，新事件还没有被执行，导致新数据使用原协议处理
        _loop->AssertInLoop(); 
        _loop->RunInLoop(std::bind(&Connection::UpgradeInLoop,this,context,conn,mesg,closed,event));
    }

};

class Acceptor {
    private:
        Socket _socket;//用于创建监听套接字
        EventLoop *_loop; //用于对监听套接字进行事件监控
        Channel _channel; //用于对监听套接字进行事件管理

        using AcceptCallback = std::function<void(int)>;
        AcceptCallback _accept_callback;
    private:
        /*监听套接字的读事件回调处理函数---获取新连接，调用_accept_callback函数进行新连接处理*/
            void HandleRead() {
                int newfd = _socket.Accept();
                if (newfd < 0) {
                    return ;
                }
                
                // int flags = fcntl(newfd, F_GETFL, 0);
                // fcntl(newfd, F_SETFL, flags | O_NONBLOCK); // 设置非阻塞
                
                if (_accept_callback) _accept_callback(newfd); 
            }
        
        int CreateServer(int port) 
        {
            assert(_socket.CreateServer(port) == true);
            return _socket.FD();
        }

    public:
        /*不能将启动读事件监控，放到构造函数中，必须在设置回调函数后，再去启动*/
        /*否则有可能造成启动监控后，立即有事件，处理的时候，回调函数还没设置：新连接得不到处理，且资源泄漏*/
        Acceptor(EventLoop *loop, int port): _socket(CreateServer(port)), _loop(loop), 
            _channel(loop, _socket.FD()) {
            _channel.SetReadCallback(std::bind(&Acceptor::HandleRead, this));
        }

        void SetAcceptCallback(const AcceptCallback &cb) 
        {
            _accept_callback = cb; 
        }

        void Listen() 
        {
            _channel.EnableRead(); 
        }
};

class LoopThread {
private:
    /*用于实现_loop获取的同步关系，避免线程创建了，但是_loop还没有实例化之前去获取_loop*/
    std::mutex _mutex;          // 互斥锁
    std::condition_variable _cond;   // 条件变量
    EventLoop *_loop;       // EventLoop指针变量，这个对象需要在线程内实例化
    std::thread _thread;    // EventLoop对应的线程
private:
    /*实例化 EventLoop 对象，唤醒_cond上有可能阻塞的线程，并且开始运行EventLoop模块的功能*/
    void ThreadEntry() {
        EventLoop loop;
        {
            std::unique_lock<std::mutex> lock(_mutex);//加锁
            _loop = &loop;
            _cond.notify_all();
        }

        loop.Start();
    }
public:
    /*创建线程，设定线程入口函数*/
    LoopThread():_loop(NULL), _thread(std::thread(&LoopThread::ThreadEntry, this)) {}
    /*返回当前线程关联的EventLoop对象指针*/
    EventLoop *GetLoop() {
        EventLoop *loop = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);//加锁
            _cond.wait(lock, [&](){ return _loop != NULL; });//loop为NULL就一直阻塞
            loop = _loop;
        }
        return loop;
    }
};

class LoopThreadPool
{
private:
    int _thread_count; //子属线程数量
    int _next_loop_index; //下一个子线程的下标
    EventLoop* _baseloop;//主线程运行的EventLoop
    std::vector<LoopThread*> _threads; //保存所有的LoopThread对象
    std::vector<EventLoop*> _loops; //子线程数量大于0时从该容器中分配EventLoop给子线程

public:
    LoopThreadPool(EventLoop* baseloop)
        :_thread_count(0),_next_loop_index(0),_baseloop(baseloop)   
    {}

    //设置子线程数量
    void SetThreadCount(int count) 
    {
        _thread_count = count;
    }

    //创建所有子线程
    void CreateThreads()
    {   
        if(_thread_count > 0)
        {
            _threads.resize(_thread_count);
            _loops.resize(_thread_count);

            for(int i = 0;i < _thread_count;i++)
            {
                //1.先创建线程
                _threads[i] = new LoopThread();
                //2.再在线程内部实例化EventLoop对象
                _loops[i] = _threads[i]->GetLoop();
            }
        }
        return ;
    }

    //使用RR轮转算法
    EventLoop* NextLoop()
    {
        if(_thread_count == 0)
        {
            return _baseloop;
        }

        _next_loop_index = (_next_loop_index + 1 ) % _thread_count;
        return _loops[_next_loop_index];
    }
};

class TcpServer
{
private:
    uint64_t _next_id;              //自动增长的connection & timer ID
    int _port;                      //服务器监听的端口
    int _timeout;                   //非活跃连接的统计时间
    bool _enable_inactive_release = false;  //非活跃连接销毁启动按钮，默认不启动
    EventLoop _base_loop;            //主线程的EventLoop
    Acceptor _acceptor;             //监听套接字的管理对象
    LoopThreadPool _thread_pool;     //子线程池 ，类内部包含了创建EventLoop分配给子线程的接口
    std::unordered_map<uint64_t,PtrConnection> _conns;//管理所有Connection连接对象

    using Functor = std::function<void()>;

    using ConnectedCallback = std::function<void(const PtrConnection &)>;           //连接回调处理
    using MessageCallback = std::function<void(const PtrConnection &, Buffer*)>; // 业务处理回调
    using ClosedCallback = std::function<void(const PtrConnection &)>; //关闭连接回调
    using AnyEventCallback = std::function<void(const PtrConnection &)>;   //任意事件回调

    ConnectedCallback _connected_callback;
    MessageCallback _message_callback;
    ClosedCallback _close_callback; 
    AnyEventCallback _event_callback;

private:
    void NewConnection(int fd) //为新连接创建一个Connection对象来管理
    {
      //  DEBUG_LOG("NEWCONNECTION CONNECTED");
        _next_id++;
        PtrConnection conn(new Connection(_thread_pool.NextLoop(),_next_id,fd));
        
        conn->SetMessageCallback(_message_callback);   //业务处理回调
        conn->SetConnectedCallback(_connected_callback);  //连接就绪完成回调
        conn->SetAnyEventCallback(_event_callback);   //任意事件回调
        conn->SetClosedCallback(_close_callback);  //连接关闭回调

        //服务器内部自己的释放回调
        conn->SetSvrCloseCallback(std::bind(&TcpServer::RemoveConnection,this,std::placeholders::_1)); 
        //这里的placeholders::_1是 调用conn的ReleaseInLoop()中，调用回调_svr_close_call_back(shared_from_this)中传递的自身这个连接Connection
        //启动非活跃超时销毁
        if(_enable_inactive_release)
            conn->EnableInactiveRelease(_timeout);
        
        //链接成功后是CONNECTING待初始化状态，现在要对该连接进行初始化
        conn->Established();
        //放入哈希表中进行管理
        _conns.insert(make_pair(_next_id,conn));    
    }

    void RemoveConnectionInLoop(const PtrConnection& conn)
    {
        int id = conn->Id();
        auto it = _conns.find(id);
        if(it == _conns.end())
        {
            _conns.erase(it);
        }
    }

    void RunAfterInLoop(const Functor& task, int delay)
    {
        _next_id++;
        //要添加的任务:task
        _base_loop.TimerAdd(_next_id,delay,task);
    }

public:
    TcpServer(int port)
        :_next_id(0),_port(port),_acceptor(&_base_loop,port),_thread_pool(&_base_loop)
    {
        //因为没有东西监控子线程创建这个事件，服务器也就不会去处理，在服务器启动前可以放在构造函数这进行一些准备工作
        //在这创建线程实际上创建的线程数量为0，因为还没SetThraedCount;
        // //1.创建线程
        // _thread_pool.CreateThreads();
        //2.设置新链接回调
        _acceptor.SetAcceptCallback(std::bind(&TcpServer::NewConnection,this,std::placeholders::_1));
        //3.将监听套接字放到_base_loop上进行监听
        _acceptor.Listen();
    }

    void Start()
    {
        //1.创建线程
        _thread_pool.CreateThreads();
        _base_loop.Start();
    }
    
    //设置超时释放时间并启动非活跃连接超时销毁按钮
    void EnableInactiveRelease(int timeout)
    {
        _timeout = timeout;
        _enable_inactive_release = true;
    }

    //添加定时任务,同样地，如果要执行的任务是属于该线程，则直接执行，否则压入任务队列
    void RunAfter(const Functor& task, int delay)
    {
        _base_loop.RunInLoop(std::bind(&TcpServer::RunAfterInLoop,this,task,delay));
    }

    //在服务器内部移除从_conns数据结构中移除一个Connection，要在线程内操作，所以还要实现...InLoop操作
    void RemoveConnection(const PtrConnection& conn)
    {
        _base_loop.RunInLoop(std::bind(&TcpServer::RemoveConnectionInLoop,this,conn));
    }

    void SetThreadCount(int count)
    {
        return _thread_pool.SetThreadCount(count);
    }

    void SetConnectedCallback(const ConnectedCallback& cb)
    {
        _connected_callback = cb;
    }
    void SetMessageCallback(const MessageCallback& cb)
    {
        _message_callback = cb;
    }
    void SetClosedCallback(const ClosedCallback& cb)
    {
        _close_callback = cb;
    }
    void SetAnyEventCallback(const AnyEventCallback& cb)
    {
        _event_callback = cb;
    }

};

//放在外面定义是因为Update和Remove将Poller和Channel整合起来了
//在Channel中只知道有Poller这个类的声明，却无法调用类内的成员函数

//Channel的Update是对外提供的接口，让Channel可以自己主动添加/修改/删除
//Poller的UpdateEvent也是对外提供的接口，这是从Poller的角度可以对各个Channel添加/....
//但是Poller的Update是不对外开放的接口，因为该接口涉及到敏感的epoll模型的操作
void Channel::Update() 
{
    _loop->UpdateEvent(this); //将this这个Channel在epoll模型中添加/修改
}
void Channel::Remove()   
{
    _loop->RemoveEvent(this); //同理
}
void TimerWheel::TimerAdd(uint64_t id, uint32_t delay,const TaskFunc& task_cb)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerAddInLoop,this,id,delay,task_cb));
}

//同理
void TimerWheel::TimerRefresh(uint64_t id)  //刷新定时任务,如果在TimerAdd里指定的添加定时任务的延时时间是5s，那么刷新定时任务后，还是延时5秒才销毁
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerRefreshInLoop,this,id));
}

void TimerWheel::TimerCancel(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerCancelInLoop,this,id));
}



//当链接断开时，Send发送数据失败会触发SIGPILE异常，将程序终止。
//我们可以忽略这个信号，就算链接断开，发送方也不会因为SIGPIPE信号而终止进程
class NetWork
{   
public:
    NetWork()
    {
        DEBUG_LOG("SIGNAL FUNCTION");
        signal(SIGPIPE,SIG_IGN);
    }
};
static NetWork nw;

#endif